--- title: "15-Spring IOC(控制反转)" created: 2025-11-26 tags: - 博客 aliases: - Spring IOC(控制反转) --- # Spring IOC(控制反转) > [!note] 定位说明 > Spring 系列第 1 篇(九部分系统讲解,1660 行)。核心回答:**对象为什么交给容器创建**——从"问题的提出"到 BeanFactory/ApplicationContext 容器组件、实际应用、与反射的结合、性能与最佳实践。前置:Class 对象与反射机制。 ## 第一部分:问题的提出 ### 一、传统方式的困境 想象一个场景: ```java // 传统方式:手动创建对象和管理依赖 public class OrderService { private OrderRepository orderRepository; private UserService userService; private PaymentService paymentService; public OrderService() { // 需要手动创建所有依赖 this.orderRepository = new OrderRepository(); this.userService = new UserService(); this.paymentService = new PaymentService(); } public void createOrder(Order order) { // 业务逻辑 userService.validateUser(order.getUserId()); orderRepository.save(order); paymentService.processPayment(order); } } // 使用时也要手动创建 OrderService orderService = new OrderService(); orderService.createOrder(order); ``` 这种方式有什么问题? 1. **耦合度高** - 直接依赖具体实现类,修改实现需要改动多处代码 2. **难以扩展** - 要替换实现类需要修改构造函数 3. **难以测试** - 单元测试无法mock依赖 4. **代码冗长** - 重复的对象创建代码 5. **依赖链复杂** - 如果OrderRepository还有其他依赖,会形成复杂的依赖链 ``` OrderService ├─ OrderRepository │ ├─ Database │ └─ Logger ├─ UserService │ ├─ UserRepository │ └─ Cache └─ PaymentService ├─ PaymentGateway └─ Logger ``` ### 二、理想的解决方案 我们希望能这样写: ```java // 理想方式:只声明依赖,框架自动处理 @Service public class OrderService { @Autowired private OrderRepository orderRepository; @Autowired private UserService userService; @Autowired private PaymentService paymentService; public void createOrder(Order order) { // 只关注业务逻辑 userService.validateUser(order.getUserId()); orderRepository.save(order); paymentService.processPayment(order); } } // 使用时直接注入,无需创建 @Autowired private OrderService orderService; orderService.createOrder(order); // 直接使用 ``` **这就是IOC要解决的问题:让框架自动管理对象的创建和依赖注入。** --- ## 第二部分:IOC的核心概念 ### 三、什么是IOC? #### 3.1 IOC的定义 **IOC(Inversion of Control,控制反转)是一种设计思想,核心是把对象的创建权和依赖管理权从代码中交给框架容器来管理。** ``` ┌──────────────────────────────────────────┐ │ IOC的本质 │ ├──────────────────────────────────────────┤ │ │ │ 传统方式: │ │ ├─ 程序员手动创建对象 │ │ ├─ 程序员手动管理依赖 │ │ └─ 程序员控制对象的生命周期 │ │ │ │ IOC方式: │ │ ├─ 框架自动创建对象 │ │ ├─ 框架自动管理依赖 │ │ └─ 框架控制对象的生命周期 │ │ │ │ 控制反转: │ │ └─ 控制权从程序员手里反转到框架手里 │ │ │ └──────────────────────────────────────────┘ ``` #### 3.2 IOC与GC的类比 ``` ┌──────────────────────────────────────────┐ │ IOC与GC的思想对比 │ ├──────────────────────────────────────────┤ │ │ │ 垃圾回收(GC) │ │ ├─ 问题:什么时候释放对象 │ │ ├─ 解决:自动回收不用的对象 │ │ └─ 效果:程序员不用手动释放内存 │ │ │ │ 控制反转(IOC) │ │ ├─ 问题:什么时候创建对象、怎么注入依赖 │ │ ├─ 解决:框架自动创建和注入 │ │ └─ 效果:程序员不用手动创建对象 │ │ │ │ 共同点: │ │ ├─ 都是"自动化"思想 │ │ ├─ 都是"把细节交给框架" │ │ └─ 都是"程序员专注业务逻辑" │ │ │ └──────────────────────────────────────────┘ ``` #### 3.3 IOC的核心优势 ``` ┌──────────────────────────────────────────┐ │ IOC的核心优势 │ ├──────────────────────────────────────────┤ │ │ │ 1. 解耦 │ │ ├─ 依赖接口而不是实现 │ │ ├─ 实现类可以随意替换 │ │ └─ 修改不会影响调用方 │ │ │ │ 2. 灵活性 │ │ ├─ 通过配置选择不同实现 │ │ ├─ 支持条件装配 │ │ └─ 支持动态代理和增强 │ │ │ │ 3. 可测试性 │ │ ├─ 容易mock依赖 │ │ ├─ 支持单元测试 │ │ └─ 支持集成测试 │ │ │ │ 4. 自动化 │ │ ├─ 自动创建对象 │ │ ├─ 自动注入依赖 │ │ └─ 自动管理生命周期 │ │ │ └──────────────────────────────────────────┘ ``` --- ## 第三部分:IOC的实现原理 ### 四、Spring IOC的四个阶段 #### 4.1 阶段概览 ``` ┌──────────────────────────────────────────┐ │ Spring IOC的四个阶段 │ ├──────────────────────────────────────────┤ │ │ │ 第1阶段:容器启动 │ │ ├─ 加载配置文件/配置类 │ │ ├─ 创建IOC容器实例 │ │ └─ 准备开始管理Bean │ │ │ │ 第2阶段:Bean定义注册 │ │ ├─ 扫描类路径 │ │ ├─ 读取注解或XML配置 │ │ ├─ 创建BeanDefinition │ │ └─ 注册到容器 │ │ │ │ 第3阶段:实例化和依赖注入 │ │ ├─ 通过反射创建Bean实例 │ │ ├─ 递归注入依赖 │ │ ├─ 支持多种注入方式 │ │ └─ 处理循环依赖 │ │ │ │ 第4阶段:初始化Bean │ │ ├─ 执行@PostConstruct方法 │ │ ├─ 执行InitializingBean接口 │ │ ├─ 执行BeanPostProcessor │ │ └─ Bean准备就绪 │ │ │ └──────────────────────────────────────────┘ ``` #### 4.2 第一阶段:容器启动 ```java // 容器启动的三种方式 // 方式1:基于XML配置 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); // 方式2:基于注解配置类 ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); // 方式3:Spring Boot自动启动 @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } // 容器启动的工作流程 public class ContainerStartupDemo { public static void main(String[] args) { // 1. 加载配置 // 2. 创建BeanFactory // 3. 创建ApplicationContext // 4. 准备开始扫描和注册Bean ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); // 5. 容器启动完成,可以获取Bean UserService userService = context.getBean(UserService.class); } } ``` #### 4.3 第二阶段:Bean定义注册 ```java // Bean定义注册的过程 // 1. 定义Bean @Component public class UserService { @Autowired private UserRepository userRepository; } @Component public class UserRepository { // ... } // 2. Spring扫描注解 // ClassPathBeanDefinitionScanner会扫描@Component及其衍生注解 // 3. 创建BeanDefinition // BeanDefinition是Bean的"说明书",包含: public class BeanDefinitionDemo { // BeanDefinition包含的信息: // - 类名:com.example.UserService // - 作用域:singleton(单例)或prototype(原型) // - 是否懒加载:false // - 初始化方法:@PostConstruct标注的方法 // - 销毁方法:@PreDestroy标注的方法 // - 依赖信息:@Autowired标注的字段 // - 其他元数据 } // 4. 注册到容器 // BeanDefinitionRegistry会把BeanDefinition注册到容器中 ``` **BeanDefinition的结构:** ```typescript public interface BeanDefinition { // 获取Bean的类名 String getBeanClassName(); // 获取作用域(singleton或prototype) String getScope(); // 是否是单例 boolean isSingleton(); // 是否是原型 boolean isPrototype(); // 是否懒加载 boolean isLazyInit(); // 获取初始化方法名 String getInitMethodName(); // 获取销毁方法名 String getDestroyMethodName(); // 获取构造函数参数 ConstructorArgumentValues getConstructorArgumentValues(); // 获取属性值 MutablePropertyValues getPropertyValues(); } ``` #### 4.4 第三阶段:实例化和依赖注入 ```java // 实例化和依赖注入的过程 public class BeanInstantiationDemo { // 假设有这样的Bean @Component public class OrderService { @Autowired private OrderRepository orderRepository; @Autowired private UserService userService; } // Spring的处理流程: // 1. 获取OrderService的BeanDefinition BeanDefinition beanDef = beanFactory.getBeanDefinition("orderService"); // 2. 通过反射创建实例 Class beanClass = Class.forName(beanDef.getBeanClassName()); OrderService orderService = beanClass.getDeclaredConstructor().newInstance(); // 3. 检查依赖 Field[] fields = beanClass.getDeclaredFields(); for (Field field : fields) { if (field.isAnnotationPresent(Autowired.class)) { // 4. 递归创建依赖的Bean Object dependency = beanFactory.getBean(field.getType()); // 5. 注入依赖 field.setAccessible(true); field.set(orderService, dependency); } } // 6. 返回完整注入的Bean return orderService; } ``` **三种注入方式:** ```java // 1. 字段注入(最常用) @Component public class UserService { @Autowired private UserRepository userRepository; } // 2. 构造器注入(推荐,便于测试) @Component public class UserService { private final UserRepository userRepository; public UserService(UserRepository userRepository) { this.userRepository = userRepository; } } // 3. Setter注入(不推荐) @Component public class UserService { private UserRepository userRepository; @Autowired public void setUserRepository(UserRepository userRepository) { this.userRepository = userRepository; } } ``` **处理循环依赖:** ```java // 循环依赖的问题 @Component public class ServiceA { @Autowired private ServiceB serviceB; // A依赖B } @Component public class ServiceB { @Autowired private ServiceA serviceA; // B依赖A } // Spring的解决方案:三级缓存 public class CircularDependencyDemo { // 第一级缓存:完整的Bean private Map singletonObjects = new HashMap<>(); // 第二级缓存:半成品Bean(已创建但未注入) private Map earlySingletonObjects = new HashMap<>(); // 第三级缓存:Bean工厂 private Map> singletonFactories = new HashMap<>(); // 解决流程: // 1. 创建ServiceA实例,放入第二级缓存 // 2. ServiceA需要ServiceB,开始创建ServiceB // 3. 创建ServiceB实例,放入第二级缓存 // 4. ServiceB需要ServiceA,从第二级缓存获取(已存在) // 5. ServiceB注入完成,放入第一级缓存 // 6. ServiceA注入完成,放入第一级缓存 } ``` #### 4.5 第四阶段:初始化Bean ```java // Bean初始化的过程 @Component public class UserService implements InitializingBean { @Autowired private UserRepository userRepository; // 1. 执行@PostConstruct方法 @PostConstruct public void init() { System.out.println("1. @PostConstruct方法执行"); // 初始化逻辑 } // 2. 执行InitializingBean接口的afterPropertiesSet方法 @Override public void afterPropertiesSet() throws Exception { System.out.println("2. InitializingBean.afterPropertiesSet()执行"); // 初始化逻辑 } // 3. 执行initMethod(在@Bean中指定) public void customInit() { System.out.println("3. initMethod执行"); // 初始化逻辑 } } // 在配置类中指定initMethod @Configuration public class AppConfig { @Bean(initMethod = "customInit") public UserService userService() { return new UserService(); } } // 4. BeanPostProcessor的前置和后置方法 @Component public class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) { System.out.println("4. BeanPostProcessor.postProcessBeforeInitialization()"); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) { System.out.println("5. BeanPostProcessor.postProcessAfterInitialization()"); // 这里可以进行代理增强 return bean; } } // 执行顺序: // 1. @PostConstruct // 2. InitializingBean.afterPropertiesSet() // 3. initMethod // 4. BeanPostProcessor.postProcessBeforeInitialization() // 5. BeanPostProcessor.postProcessAfterInitialization() ``` --- ## 第四部分:IOC容器的核心组件 ### 五、BeanFactory与ApplicationContext #### 5.1 两者的关系 ``` ┌──────────────────────────────────────────┐ │ BeanFactory与ApplicationContext │ ├──────────────────────────────────────────┤ │ │ │ BeanFactory(低级容器) │ │ ├─ 职责:创建和管理Bean │ │ ├─ 功能:基础的Bean生命周期管理 │ │ ├─ 性能:轻量级 │ │ └─ 用途:底层框架 │ │ │ │ ApplicationContext(高级容器) │ │ ├─ 继承:extends BeanFactory │ │ ├─ 职责:提供更多企业级功能 │ │ ├─ 功能: │ │ │ ├─ Bean生命周期管理 │ │ │ ├─ 国际化支持 │ │ │ ├─ 事件发布 │ │ │ ├─ 资源加载 │ │ │ └─ AOP支持 │ │ ├─ 性能:相对较重 │ │ └─ 用途:应用程序 │ │ │ └──────────────────────────────────────────┘ ``` #### 5.2 ApplicationContext的实现类 ```java // 1. ClassPathXmlApplicationContext - 从classpath加载XML配置 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); // 2. FileSystemXmlApplicationContext - 从文件系统加载XML配置 ApplicationContext context = new FileSystemXmlApplicationContext("/path/to/applicationContext.xml"); // 3. AnnotationConfigApplicationContext - 从注解配置类加载 ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); // 4. AnnotationConfigWebApplicationContext - Web应用的注解配置 // 在Spring MVC中使用 // 5. WebApplicationContext - Web应用的容器 // 通过DispatcherServlet创建 ``` #### 5.3 BeanFactory的工作原理 ```java public class BeanFactoryDemo { public static void main(String[] args) { // 1. 创建BeanFactory BeanFactory beanFactory = new DefaultListableBeanFactory(); // 2. 注册BeanDefinition BeanDefinition beanDef = new RootBeanDefinition(UserService.class); ((DefaultListableBeanFactory) beanFactory).registerBeanDefinition("userService", beanDef); // 3. 获取Bean(延迟初始化) UserService userService = beanFactory.getBean("userService", UserService.class); // BeanFactory特点: // - 延迟初始化:getBean时才创建 // - 轻量级:只管理Bean的创建 // - 不支持国际化、事件等高级功能 } } ``` --- ## 第五部分:IOC的实际应用 ### 六、Spring中的IOC应用 #### 6.1 组件扫描和自动装配 ```java // 1. 定义配置类 @Configuration @ComponentScan(basePackages = "com.example") public class AppConfig { } // 2. 定义Bean @Component public class UserRepository { public User findById(int id) { return new User(id, "Tom"); } } @Service public class UserService { @Autowired private UserRepository userRepository; public User getUser(int id) { return userRepository.findById(id); } } @Controller public class UserController { @Autowired private UserService userService; public void handleRequest(int id) { User user = userService.getUser(id); } } // 3. 启动容器 public class Application { public static void main(String[] args) { ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); // 4. 获取Bean UserController controller = context.getBean(UserController.class); controller.handleRequest(1); } } // Spring的处理流程: // 1. 扫描@ComponentScan指定的包 // 2. 找到@Component及其衍生注解(@Service、@Controller等) // 3. 为每个类创建BeanDefinition // 4. 创建Bean实例 // 5. 通过@Autowired注入依赖 // 6. 执行初始化方法 // 7. Bean准备就绪 ``` #### 6.2 条件装配 ```java // 根据条件选择不同的Bean实现 // 1. 定义接口 public interface DataSource { Connection getConnection(); } // 2. 定义多个实现 @Component @ConditionalOnProperty(name = "db.type", havingValue = "mysql") public class MysqlDataSource implements DataSource { @Override public Connection getConnection() { return new MysqlConnection(); } } @Component @ConditionalOnProperty(name = "db.type", havingValue = "postgresql") public class PostgresqlDataSource implements DataSource { @Override public Connection getConnection() { return new PostgresqlConnection(); } } // 3. 注入时自动选择 @Service public class UserService { @Autowired private DataSource dataSource; // 根据配置自动选择实现 } // 4. 配置文件 // application.properties // db.type=mysql ``` #### 6.3 Bean的作用域 ```java // 1. Singleton(单例)- 默认 @Component @Scope("singleton") public class SingletonBean { // 整个应用只有一个实例 } // 2. Prototype(原型) @Component @Scope("prototype") public class PrototypeBean { // 每次获取都创建新实例 } // 3. Request(请求作用域)- Web应用 @Component @Scope("request") public class RequestBean { // 每个HTTP请求创建一个实例 } // 4. Session(会话作用域)- Web应用 @Component @Scope("session") public class SessionBean { // 每个HTTP会话创建一个实例 } // 验证作用域 public class ScopeDemo { public static void main(String[] args) { ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); // Singleton验证 SingletonBean bean1 = context.getBean(SingletonBean.class); SingletonBean bean2 = context.getBean(SingletonBean.class); System.out.println(bean1 == bean2); // true,同一个实例 // Prototype验证 PrototypeBean bean3 = context.getBean(PrototypeBean.class); PrototypeBean bean4 = context.getBean(PrototypeBean.class); System.out.println(bean3 == bean4); // false,不同实例 } } ``` #### 6.4 Bean的生命周期管理 ```java // Bean的完整生命周期 @Component public class LifecycleBean implements InitializingBean, DisposableBean { private String name; // 1. 构造函数 public LifecycleBean() { System.out.println("1. 构造函数执行"); } // 2. 属性注入(通过反射) public void setName(String name) { System.out.println("2. 属性注入"); this.name = name; } // 3. BeanNameAware接口 @Override public void setBeanName(String name) { System.out.println("3. setBeanName()执行"); } // 4. BeanFactoryAware接口 @Override public void setBeanFactory(BeanFactory beanFactory) { System.out.println("4. setBeanFactory()执行"); } // 5. ApplicationContextAware接口 @Override public void setApplicationContext(ApplicationContext applicationContext) { System.out.println("5. setApplicationContext()执行"); } // 6. BeanPostProcessor的前置方法 // 由Spring框架调用 // 7. @PostConstruct注解 @PostConstruct public void init() { System.out.println("7. @PostConstruct执行"); } // 8. InitializingBean接口 @Override public void afterPropertiesSet() throws Exception { System.out.println("8. InitializingBean.afterPropertiesSet()执行"); } // 9. BeanPostProcessor的后置方法 // 由Spring框架调用 // 10. 正常使用 public void doSomething() { System.out.println("10. Bean正常使用"); } // 11. @PreDestroy注解 @PreDestroy public void cleanup() { System.out.println("11. @PreDestroy执行"); } // 12. DisposableBean接口 @Override public void destroy() throws Exception { System.out.println("12. DisposableBean.destroy()执行"); } } // 执行顺序: // 1. 构造函数 // 2. 属性注入 // 3. setBeanName() // 4. setBeanFactory() // 5. setApplicationContext() // 6. BeanPostProcessor.postProcessBeforeInitialization() // 7. @PostConstruct // 8. InitializingBean.afterPropertiesSet() // 9. BeanPostProcessor.postProcessAfterInitialization() // 10. Bean正常使用 // 11. @PreDestroy // 12. DisposableBean.destroy() ``` --- ## 第六部分:IOC与其他机制的结合 ### 七、IOC与AOP的结合 ```java // IOC创建Bean,AOP为Bean增强 // 1. 定义业务接口 public interface UserService { void save(User user); } // 2. 实现业务接口 @Service public class UserServiceImpl implements UserService { @Autowired private UserRepository userRepository; @Override @Transactional public void save(User user) { userRepository.save(user); } } // 3. 定义切面 @Aspect @Component public class LoggingAspect { @Before("execution(* com.example.service.*.*(..))") public void beforeMethod(JoinPoint joinPoint) { System.out.println("方法调用前:" + joinPoint.getSignature()); } @After("execution(* com.example.service.*.*(..))") public void afterMethod(JoinPoint joinPoint) { System.out.println("方法调用后:" + joinPoint.getSignature()); } } // 4. IOC和AOP的协作 public class IOCAndAOPDemo { public static void main(String[] args) { ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); // IOC创建Bean UserService userService = context.getBean(UserService.class); // 实际上获取的是代理对象 System.out.println(userService.getClass().getName()); // 输出:com.sun.proxy.$Proxy0(JDK动态代理) // 或:com.example.UserServiceImpl$$EnhancerByCGLIB$$xxx(CGLIB代理) // 调用方法时,AOP会织入增强逻辑 userService.save(new User()); // 输出: // 方法调用前:... // 保存用户 // 方法调用后:... } } // IOC和AOP的工作流程: // 1. IOC扫描@Service注解,创建UserServiceImpl的BeanDefinition // 2. IOC创建UserServiceImpl实例 // 3. IOC注入依赖 // 4. AOP检测到@Transactional注解 // 5. AOP创建代理对象,包装UserServiceImpl // 6. 将代理对象放入容器 // 7. 调用代理对象的方法时,AOP织入增强逻辑 ``` ### 八、IOC与注解的结合 ```java // 注解驱动的IOC // 1. 元注解定义 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface MyService { String value() default ""; } // 2. 自定义注解处理器 @Component public class MyServiceBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { // 扫描@MyService注解 ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry); scanner.addIncludeFilter((metadataReader, metadataReaderFactory) -> { return metadataReader.getClassMetadata() .hasAnnotation(MyService.class.getName()); }); // 注册BeanDefinition scanner.scan("com.example"); } } // 3. 使用自定义注解 @MyService("userService") public class UserService { public void save(User user) { System.out.println("保存用户"); } } // 4. 注解驱动的依赖注入 @MyService("orderService") public class OrderService { @Autowired private UserService userService; public void createOrder(Order order) { userService.save(order.getUser()); } } // Spring通过反射读取注解,自动完成Bean的创建和注入 ``` --- ## 第七部分:IOC的性能与最佳实践 ### 九、IOC的性能考虑 #### 9.1 启动性能 ```java // IOC容器启动的性能开销 public class StartupPerformanceDemo { public static void main(String[] args) { // 测试启动时间 long startTime = System.currentTimeMillis(); ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); long endTime = System.currentTimeMillis(); System.out.println("容器启动耗时:" + (endTime - startTime) + "ms"); // 性能开销来自: // 1. 类扫描 - 扫描classpath中的所有类 // 2. 注解解析 - 通过反射读取注解信息 // 3. BeanDefinition创建 - 为每个Bean创建定义 // 4. Bean实例化 - 通过反射创建实例 // 5. 依赖注入 - 递归注入所有依赖 // 6. 初始化方法执行 - 执行@PostConstruct等 } } ``` #### 9.2 性能优化建议 ```java // 1. 使用懒加载 @Component @Lazy public class HeavyBean { // 只在第一次使用时才创建 } // 2. 缩小扫描范围 @Configuration @ComponentScan(basePackages = "com.example.service") // 只扫描service包 public class AppConfig { } // 3. 使用@Bean而不是@Component @Configuration public class AppConfig { @Bean public UserService userService() { // 显式创建,避免注解扫描 return new UserService(); } } // 4. 避免循环依赖 // 循环依赖会增加初始化时间 // 应该重新设计架构避免循环依赖 // 5. 使用条件装配减少Bean数量 @Component @ConditionalOnProperty(name = "feature.enabled", havingValue = "true") public class OptionalBean { // 只在特定条件下创建 } // 6. 使用Spring Boot的自动配置 // Spring Boot已经优化了启动性能 @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } ``` ### 十、IOC的最佳实践 #### 10.1 推荐做法 ```java // 1. 优先使用构造器注入 @Service public class UserService { private final UserRepository userRepository; private final UserValidator userValidator; // 构造器注入的优势: // - 依赖不可变 // - 便于测试 // - 清晰表达依赖关系 public UserService(UserRepository userRepository, UserValidator userValidator) { this.userRepository = userRepository; this.userValidator = userValidator; } } // 2. 依赖接口而不是实现 @Service public class OrderService { private final PaymentService paymentService; // 依赖接口 public OrderService(PaymentService paymentService) { this.paymentService = paymentService; } } // 3. 使用@Qualifier消除歧义 @Service public class OrderService { @Autowired @Qualifier("alipayService") private PaymentService paymentService; } // 4. 为Bean提供有意义的名称 @Service("userService") // 明确指定Bean名称 public class UserServiceImpl implements UserService { } // 5. 使用配置类而不是XML @Configuration public class AppConfig { @Bean public UserRepository userRepository() { return new UserRepositoryImpl(); } @Bean public UserService userService(UserRepository userRepository) { return new UserServiceImpl(userRepository); } } // 6. 合理使用作用域 @Service @Scope("singleton") // 大多数情况下使用单例 public class UserService { } // 7. 实现接口便于测试和扩展 public interface UserService { void save(User user); } @Service public class UserServiceImpl implements UserService { @Override public void save(User user) { } } // 8. 使用@Autowired(required = false)处理可选依赖 @Service public class UserService { @Autowired(required = false) private UserCache userCache; // 可选依赖 } // 9. 避免在Bean中使用静态变量 // ❌ 不好的做法 @Service public class UserService { private static UserRepository userRepository; // 静态变量 } // ✅ 好的做法 @Service public class UserService { private final UserRepository userRepository; // 实例变量 } // 10. 使用@ConfigurationProperties进行配置 @Component @ConfigurationProperties(prefix = "app.user") public class UserProperties { private String defaultName; private int defaultAge; // getter/setter } ``` #### 10.2 避免做法 ```java // ❌ 不要使用字段注入 @Service public class BadUserService { @Autowired private UserRepository userRepository; // 字段注入 // 问题: // 1. 依赖隐藏,不清楚需要什么 // 2. 难以测试,无法通过构造器传入mock对象 // 3. 可能为null,容易出现NPE // 4. 依赖可变,容易被修改 } // ❌ 不要在Bean中创建其他Bean @Service public class BadOrderService { public void createOrder(Order order) { // ❌ 不要这样做 UserService userService = new UserService(); userService.save(order.getUser()); } } // ✅ 应该注入 @Service public class GoodOrderService { private final UserService userService; public GoodOrderService(UserService userService) { this.userService = userService; } public void createOrder(Order order) { userService.save(order.getUser()); } } // ❌ 不要在Bean中使用ApplicationContext.getBean() @Service public class BadService { @Autowired private ApplicationContext applicationContext; public void doSomething() { // ❌ 不要这样做 UserService userService = applicationContext.getBean(UserService.class); } } // ✅ 应该直接注入 @Service public class GoodService { private final UserService userService; public GoodService(UserService userService) { this.userService = userService; } } // ❌ 不要创建过多的单例Bean @Configuration public class BadConfig { @Bean public Bean1 bean1() { return new Bean1(); } @Bean public Bean2 bean2() { return new Bean2(); } // ... 创建100个Bean // 问题:启动慢,内存占用大 } // ✅ 应该按需创建 @Configuration public class GoodConfig { @Bean @ConditionalOnProperty(name = "feature.enabled") public OptionalBean optionalBean() { return new OptionalBean(); } } // ❌ 不要在Bean中做重操作 @Component public class BadBean { public BadBean() { // ❌ 不要在构造函数中做重操作 loadLargeFile(); queryDatabase(); } } // ✅ 应该在初始化方法中做 @Component public class GoodBean { @PostConstruct public void init() { // ✅ 在@PostConstruct中做重操作 loadLargeFile(); queryDatabase(); } } // ❌ 不要创建循环依赖 @Service public class ServiceA { @Autowired private ServiceB serviceB; // A依赖B } @Service public class ServiceB { @Autowired private ServiceA serviceA; // B依赖A } // ✅ 应该重新设计避免循环依赖 @Service public class ServiceA { @Autowired private ServiceC serviceC; } @Service public class ServiceB { @Autowired private ServiceC serviceC; } @Service public class ServiceC { // 不依赖A和B } ``` --- ## 第八部分:IOC的高级特性 ### 十一、Bean的条件装配 ```java // 根据条件选择不同的Bean // 1. @ConditionalOnProperty - 根据配置属性 @Component @ConditionalOnProperty(name = "cache.enabled", havingValue = "true") public class CacheService { // 只在cache.enabled=true时创建 } // 2. @ConditionalOnClass - 根据类是否存在 @Component @ConditionalOnClass(name = "redis.clients.jedis.Jedis") public class RedisService { // 只在Redis客户端库存在时创建 } // 3. @ConditionalOnMissingBean - 根据Bean是否存在 @Configuration public class AppConfig { @Bean @ConditionalOnMissingBean public UserRepository userRepository() { return new DefaultUserRepository(); } } // 4. @ConditionalOnExpression - 根据SpEL表达式 @Component @ConditionalOnExpression("${feature.enabled:false}") public class FeatureService { // 只在表达式为true时创建 } // 5. 自定义Condition public class MyCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { // 自定义条件逻辑 return context.getEnvironment().getProperty("my.feature").equals("enabled"); } } @Component @Conditional(MyCondition.class) public class MyService { // 只在自定义条件满足时创建 } ``` ### 十二、Bean的事件机制 ```java // Spring IOC支持事件发布和监听 // 1. 定义事件 public class UserCreatedEvent extends ApplicationEvent { private final User user; public UserCreatedEvent(Object source, User user) { super(source); this.user = user; } public User getUser() { return user; } } // 2. 发布事件 @Service public class UserService { @Autowired private ApplicationEventPublisher eventPublisher; public void createUser(User user) { // 保存用户 userRepository.save(user); // 发布事件 eventPublisher.publishEvent(new UserCreatedEvent(this, user)); } } // 3. 监听事件 @Component public class UserCreatedListener implements ApplicationListener { @Override public void onApplicationEvent(UserCreatedEvent event) { User user = event.getUser(); System.out.println("用户创建事件:" + user.getName()); // 发送邮件、记录日志等 } } // 4. 使用@EventListener注解 @Component public class UserEventHandler { @EventListener public void handleUserCreated(UserCreatedEvent event) { System.out.println("用户创建:" + event.getUser().getName()); } @EventListener public void handleUserDeleted(UserDeletedEvent event) { System.out.println("用户删除:" + event.getUser().getName()); } } ``` ### 十三、Bean的后处理器 ```java // BeanPostProcessor用于在Bean初始化前后进行处理 // 1. 实现BeanPostProcessor接口 @Component public class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) { System.out.println("初始化前:" + beanName); // 可以在这里修改Bean return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) { System.out.println("初始化后:" + beanName); // 可以在这里创建代理 if (bean instanceof UserService) { return createProxy(bean); } return bean; } private Object createProxy(Object bean) { // 创建代理对象 return Proxy.newProxyInstance( bean.getClass().getClassLoader(), bean.getClass().getInterfaces(), (proxy, method, args) -> { System.out.println("代理方法:" + method.getName()); return method.invoke(bean, args); } ); } } // 2. BeanFactoryPostProcessor - 处理BeanDefinition @Component public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { // 可以在这里修改BeanDefinition BeanDefinition beanDef = beanFactory.getBeanDefinition("userService"); beanDef.setScope("prototype"); // 改为原型作用域 } } ``` --- ## 第九部分:总结 ### 十四、IOC的本质思考 **IOC(控制反转)是一种设计思想,通过将对象的创建权和依赖管理权交给框架容器,实现了代码的解耦、灵活性和可维护性的提升。** ``` ┌──────────────────────────────────────────┐ │ IOC的核心价值 │ ├──────────────────────────────────────────┤ │ │ │ 1. 解耦 │ │ ├─ 依赖接口而不是实现 │ │ ├─ 实现类可以随意替换 │ │ └─ 修改不会影响调用方 │ │ │ │ 2. 灵活性 │ │ ├─ 通过配置选择不同实现 │ │ ├─ 支持条件装配 │ │ └─ 支持动态代理和增强 │ │ │ │ 3. 可测试性 │ │ ├─ 容易mock依赖 │ │ ├─ 支持单元测试 │ │ └─ 支持集成测试 │ │ │ │ 4. 自动化 │ │ ├─ 自动创建对象 │ │ ├─ 自动注入依赖 │ │ └─ 自动管理生命周期 │ │ │ │ 5. 可维护性 │ │ ├─ 配置集中管理 │ │ ├─ 易于扩展 │ │ └─ 代码更清晰 │ │ │ └──────────────────────────────────────────┘ ``` ### 十五、IOC的四个阶段总结 ``` ┌──────────────────────────────────────────┐ │ IOC的四个阶段总结 │ ├──────────────────────────────────────────┤ │ │ │ 第1阶段:容器启动 │ │ ├─ 加载配置文件/配置类 │ │ ├─ 创建IOC容器实例 │ │ └─ 准备开始管理Bean │ │ │ │ 第2阶段:Bean定义注册 │ │ ├─ 扫描类路径 │ │ ├─ 读取注解或XML配置 │ │ ├─ 创建BeanDefinition │ │ └─ 注册到容器 │ │ │ │ 第3阶段:实例化和依赖注入 │ │ ├─ 通过反射创建Bean实例 │ │ ├─ 递归注入依赖 │ │ ├─ 支持多种注入方式 │ │ └─ 处理循环依赖 │ │ │ │ 第4阶段:初始化Bean │ │ ├─ 执行@PostConstruct方法 │ │ ├─ 执行InitializingBean接口 │ │ ├─ 执行BeanPostProcessor │ │ └─ Bean准备就绪 │ │ │ └──────────────────────────────────────────┘ ``` ### 十六、IOC与反射、动态代理的关系 ``` ┌──────────────────────────────────────────┐ │ IOC、反射、动态代理的关系 │ ├──────────────────────────────────────────┤ │ │ │ 反射(Reflection) │ │ ├─ 本质:运行时获取类信息 │ │ ├─ 作用:IOC的基础 │ │ └─ 用途:创建对象、注入依赖 │ │ │ │ IOC(Inversion of Control) │ │ ├─ 本质:控制权反转 │ │ ├─ 作用:自动创建和管理Bean │ │ └─ 用途:解耦、灵活、可维护 │ │ │ │ 动态代理(Dynamic Proxy) │ │ ├─ 本质:运行时生成代理类 │ │ ├─ 作用:AOP的基础 │ │ └─ 用途:织入增强逻辑 │ │ │ │ 三者的协作: │ │ ├─ 反射:IOC用反射创建对象 │ │ ├─ IOC:创建Bean并注入依赖 │ │ ├─ 动态代理:为Bean创建代理 │ │ └─ AOP:通过代理织入增强逻辑 │ │ │ └──────────────────────────────────────────┘ ``` --- ## 十七、关键要点回顾 ### 17.1 IOC的核心概念 | 概念 | 说明 | 用途 | | --- | --- | --- | | **BeanFactory** | 低级容器 | 基础Bean管理 | | **ApplicationContext** | 高级容器 | 企业级应用 | | **BeanDefinition** | Bean的定义 | 描述Bean的元信息 | | **Bean** | 容器管理的对象 | 应用中的业务对象 | | **依赖注入** | 自动注入依赖 | 解耦和灵活 | | **作用域** | Bean的生命周期 | singleton/prototype等 | ### 17.2 三种注入方式对比 | 方式 | 优点 | 缺点 | 推荐度 | | --- | --- | --- | --- | | **构造器注入** | 依赖清晰、不可变、易测试 | 参数多时复杂 | ⭐⭐⭐⭐⭐ | | **字段注入** | 简洁 | 隐藏依赖、难测试、可变 | ⭐ | | **Setter注入** | 灵活 | 依赖可变、不清晰 | ⭐⭐ | ### 17.3 Bean的生命周期 ``` 构造函数 → 属性注入 → Aware接口 → BeanPostProcessor前置 → @PostConstruct → InitializingBean → BeanPostProcessor后置 → 正常使用 → @PreDestroy → DisposableBean ``` --- ## 十八、记忆口诀 ``` IOC是思想,容器来管理 Bean的创建,依赖的注入 四个阶段走,启动注册实例化 初始化完成,Bean就准备好 反射是基础,动态代理增强 AOP织入逻辑,框架自动完成 程序员声明,框架来实现 构造器注入最推荐,字段注入要避免 依赖接口不实现,灵活扩展最关键 单例默认用,原型按需要 BeanFactory轻量级,ApplicationContext功能全 启动会慢点,但好处多得很 解耦灵活可扩展,可维护性最关键 ``` --- ## 十九、相关链接 - 01-Class对象与反射机制 - IOC的基础 - [[7-Blog/后端与微服务/14-动态代理|动态代理]] - AOP的基础 - [[7-Blog/后端与微服务/13-注解原理|注解原理]] - 注解驱动IOC - Spring AOP(面向切面编程) - IOC与AOP的结合 --- ## 二十、常见问题解答 ### Q1: IOC和DI有什么区别? **答:** - **IOC(控制反转)** - 是一种设计思想,强调控制权的反转 - **DI(依赖注入)** - 是实现IOC的一种方式,强调依赖的注入 - 关系:IOC是目标,DI是手段 ### Q2: 为什么Spring默认使用单例而不是原型? **答:** - 单例性能更好,避免频繁创建对象 - 单例内存占用少 - 大多数Bean是无状态的,可以安全共享 - 如果Bean有状态,应该使用原型或其他作用域 ### Q3: 循环依赖为什么会发生? **答:** ``` A依赖B,B依赖A 或者更复杂的链式依赖:A→B→C→A ``` ### Q4: Spring如何解决循环依赖? **答:** - 使用三级缓存机制 - 第一级:完整的Bean - 第二级:半成品Bean(已创建但未注入) - 第三级:Bean工厂 ### Q5: 为什么推荐使用构造器注入? **答:** - 依赖清晰,一目了然 - 依赖不可变,线程安全 - 便于单元测试 - 强制依赖必须提供 ### Q6: @Autowired和@Resource有什么区别? **答:** - **@Autowired** - Spring提供,按类型注入 - **@Resource** - Java标准,按名称注入 - 推荐使用@Autowired ---